home *** CD-ROM | disk | FTP | other *** search
/ PC Format Collection 21 / PC Format CD-ROM Collection 21 (1995-12)(Future Publishing)(GB)[issue 51].iso / resource / flisumry.poc < prev    next >
Text File  |  1992-08-17  |  15KB  |  453 lines

  1. /*****************************************************************************
  2.  * FLISUMRY.POC: Summarize a flic by reducing frames to postage stamp images.
  3.  *
  4.  * MAINTENANCE:
  5.  *    03/01/91    Ian Lepore
  6.  *                Created.
  7.  *    10/15/91    Ian
  8.  *                Reworked, now uses new PSTAMP.POE and has more features.
  9.  *    09/17/92    Ian
  10.  *                Fixed an off-by-one bug that was being caused by cumulative
  11.  *                floating point rounding error when adding offset_to_nextframe.
  12.  *                Now a multiply is used instead of cumulative addition.
  13.  ****************************************************************************/
  14.  
  15. #pragma poco library "pstamp.poe"
  16. #include "errcodes.h"
  17.  
  18. /*----------------------------------------------------------------------------
  19.  * the first release of pj/poco didn't include an Err_range error; if
  20.  * errcodes.h hasn't defined it, we'll define it here to a similar error.
  21.  *--------------------------------------------------------------------------*/
  22.  
  23. #ifndef Err_range
  24.   #define Err_range Err_parameter_range
  25. #endif
  26.  
  27. /*----------------------------------------------------------------------------
  28.  * main menu...
  29.  *--------------------------------------------------------------------------*/
  30.  
  31. char main_curgrid_template[] = "Set Grid (Now %d x %d)";
  32. char main_curgrid_string[4+sizeof(main_curgrid_template)];
  33.  
  34. char main_menu_title[] = "Summarize Flic Frames:";
  35. char *main_menu[] = {
  36.     "Current Flic",
  37.     "Flic from Disk",
  38.     main_curgrid_string,
  39.     "Help",
  40.     "Exit",
  41.     };
  42.  
  43. /*----------------------------------------------------------------------------
  44.  * grid size menu...
  45.  *--------------------------------------------------------------------------*/
  46.  
  47. char grid_title[] = "Dimension for summary grid:";
  48. char *grid_choices[] = {
  49.     "Custom Size",
  50.     "2 x 2",
  51.     "3 x 3",
  52.     "4 x 4",
  53.     "5 x 5",
  54.     "6 x 6",
  55.     "7 x 7",
  56.     "8 x 8",
  57.     "9 x 9",
  58.     "Cancel"
  59.     };
  60.  
  61. /*----------------------------------------------------------------------------
  62.  * various "are you sure?" prompts...
  63.  *--------------------------------------------------------------------------*/
  64.  
  65. char replace_flic_prompt[] = "You have %d unsaved changes.\n\n"
  66.                              "Okay to discard changes and create a "
  67.                              "new flic containing the summary?"
  68.                              ;
  69. char replace_cel_prompt[]  = "Okay to discard current contents of Cel/AnimCel?";
  70. char replace_swap_prompt[] = "Okay to discard current contents of Swap Screen?";
  71. char disk_flicpath_prompt[] = "Please choose flic to summarize:";
  72.  
  73. /*----------------------------------------------------------------------------
  74.  * misc stuff...
  75.  *--------------------------------------------------------------------------*/
  76.  
  77. Boolean is_okay_to_replace_cel    = FALSE;
  78. Boolean is_okay_to_replace_swap = FALSE;
  79.  
  80. char    grid_option_gvar[]     = "$flisumry_grid_option";
  81. char    disk_flicpath_gvar[] = "$flisumry_lastpath";
  82.  
  83. int     grid_dimension;     // 3 == 3x3 grid, 4 == 4x4, etc.
  84.  
  85. void do_help(void)
  86. /*****************************************************************************
  87.  * give a little help on what the program is all about.
  88.  ****************************************************************************/
  89. {
  90.     Qtext(
  91.  
  92.         "This program summarizes a flic by creating a screen full of small "
  93.         "'postage stamp' images from the flic's frames.  It can summarize "
  94.         "the flic currently in memory, placing the results in the swap "
  95.         "screen, or it can summarize a flic stored on disk, placing the "
  96.         "results in the current flic frame."
  97.         "\n\n"
  98.         "When the current flic is summarized, the resulting summary screen "
  99.         "is always the same resolution as the flic itself."
  100.         "\n\n"
  101.         "When a flic "
  102.         "from disk is summarized, it may have different dimensions than the "
  103.         "current flic frame.  Thus, you can summarize a disk flic onto a "
  104.         "frame with a larger resolution, and get larger postage stamps "
  105.         "images in the summary."
  106.  
  107.          );
  108. }
  109.  
  110. void get_grid_choice(Boolean do_dialog)
  111. /*****************************************************************************
  112.  * get the user's preference for the postage stamp grid.
  113.  *    if the do_dialog flag is true, we ask the user via Qmenu().  if the flag
  114.  *    is false, we retrieve the saved setting from the global variable pool.
  115.  *    when the user changes the value via the dialog, we store the new value
  116.  *    into the global variable for next time we're run.
  117.  ****************************************************************************/
  118. {
  119.     int     option;
  120.     char    stored_option[10] = "0";
  121.  
  122.     if (do_dialog) {
  123.         option = Qmenu(grid_choices, Array_els(grid_choices), grid_title);
  124.         if (option == 1) {
  125.             option = grid_dimension;
  126.             Qnumber(&option, 2, 25, "Custom X by X grid, select value of X:");
  127.             if (option < 2 || option > 25) {
  128.                 Qerror(Err_range, "Value must be between 2 and 25 inclusive");
  129.                 return;
  130.             }
  131.         }
  132.         sprintf(stored_option, "%d", option);
  133.         GlobalVarSet(grid_option_gvar, stored_option);
  134.     } else {
  135.         GlobalVarGet(grid_option_gvar, stored_option);
  136.         option = atoi(stored_option);
  137.         if (option < 2 || option > 25)
  138.             option = 4;
  139.     }
  140.  
  141.     if (option > 0) {
  142.         grid_dimension = option;
  143.         sprintf(main_curgrid_string, main_curgrid_template,
  144.                     grid_dimension, grid_dimension);
  145.     }
  146. }
  147.  
  148. char *ordinal(int num)
  149. /*****************************************************************************
  150.  * return the suffix for a number to make the number ordinal.
  151.  ****************************************************************************/
  152. {
  153.     int         idx;
  154.     static char ordsuffix[10];
  155.     static char *suffi[] = {"th","st","nd","rd"};
  156.  
  157.     idx = num % 10;
  158.     if ((num > 10 && num < 20) || idx > 3)
  159.         idx = 0;
  160.     sprintf(ordsuffix,"%d%s", num, suffi[idx]);
  161.     return ordsuffix;
  162. }
  163.  
  164. Errcode summarize_current_flic(void)
  165. /*****************************************************************************
  166.  * summarize the current flic into the swap screen.
  167.  ****************************************************************************/
  168. {
  169.     Errcode err;
  170.     int     dx, dy;
  171.     int     dw, dh;
  172.     int     sw, sh;
  173.     int     linecount;
  174.     int     num_pstamps;
  175.     int     curpstamp;
  176.     int     change_count;
  177.     int     num_flic_frames;
  178.     double    offset_to_nextframe;
  179.     double    curflicframe;
  180.     Screen    *swapscrn;
  181.     Screen    *picscrn;
  182.  
  183.     if (SwapExists()) {
  184.         if (!is_okay_to_replace_swap) {
  185.             if (!Qquestion(replace_swap_prompt))
  186.                 return Err_abort;
  187.         }
  188.     }
  189.     is_okay_to_replace_swap = TRUE; // only ask once during a run
  190.  
  191.     if (1 >= (num_flic_frames = GetFrameCount())) {
  192.         Qtext("Cannot create a summary of a single-frame flic!");
  193.         return Err_reported;
  194.     }
  195.  
  196.     num_pstamps = grid_dimension * grid_dimension;
  197.  
  198.     if (num_pstamps > num_flic_frames)
  199.         num_pstamps = num_flic_frames;
  200.  
  201.     offset_to_nextframe = (double)num_flic_frames / num_pstamps;
  202.     if (offset_to_nextframe < 1.0)
  203.         offset_to_nextframe = 1.0;
  204.  
  205.     SwapClip();     // make a swap screen
  206.  
  207.     picscrn  = GetPicScreen();
  208.     swapscrn = GetSwapScreen();
  209.  
  210.     GetScreenSize(picscrn, &dw, &dh);
  211.     dw = (dw / grid_dimension) - 1;
  212.     dh = (dh / grid_dimension) - 1;
  213.  
  214.     curflicframe = 0.0;
  215.     curpstamp = 1;
  216.  
  217.     InitPstampScreen(swapscrn);
  218.  
  219.     for (dy = 0; curpstamp <= num_pstamps; dy += dh) {
  220.         for (dx = 0, linecount = 0; linecount < grid_dimension && curpstamp <= num_pstamps; dx += dw, ++linecount) {
  221.             SetFrame((int)curflicframe);
  222.             printf("Processing frame %d, the %s of %d in the summary",
  223.                     (int)curflicframe, ordinal(curpstamp), num_pstamps);
  224.             MakePstamp(picscrn, swapscrn, dx, dy, dw, dh, TRUE);
  225.             ++curpstamp;
  226.             curflicframe += offset_to_nextframe;
  227.         }
  228.     }
  229.  
  230.     CleanupPstampScreen(swapscrn);
  231.  
  232.     Qtext("Summary completed successfully, results are in the swap screen.");
  233.  
  234.     unprintf();
  235.     return err;
  236. }
  237.  
  238. int ask_frame_count(int num_cel_frames, int pstamps_per_frame)
  239. /*****************************************************************************
  240.  * we have more input frames that will fit in one output frame, ask the user
  241.  * how many output frames should appear in the summary.
  242.  ****************************************************************************/
  243. {
  244.     int         full_summary_frame_count;
  245.     int         requested_frame_count;
  246.     static char prompt[] = "There are %d input frames.  "
  247.                        "Summarizing all input frames "
  248.                        "will create %d output frames.  "
  249.                        "If fewer output frames "
  250.                        "are selected, some input "
  251.                        "frames will be skipped."
  252.                        "\n\n"
  253.                        "Please choose the number of output frames:"
  254.                        ;
  255.     char        formatted_prompt[15+sizeof(prompt)];
  256.  
  257.     full_summary_frame_count = (num_cel_frames+pstamps_per_frame-1)/pstamps_per_frame;
  258.  
  259.     sprintf(formatted_prompt, prompt, num_cel_frames, full_summary_frame_count);
  260.  
  261.     requested_frame_count = full_summary_frame_count;
  262.     if (!Qnumber(&requested_frame_count, 1, full_summary_frame_count, formatted_prompt))
  263.         return Err_abort;
  264.  
  265.     if (requested_frame_count > full_summary_frame_count)
  266.         return full_summary_frame_count;
  267.     else
  268.         return requested_frame_count;
  269.  
  270. }
  271.  
  272. Errcode summarize_disk_flic(char *flicpath)
  273. /*****************************************************************************
  274.  * summarize a flic from disk into the current flic.
  275.  ****************************************************************************/
  276. {
  277.     Errcode err;
  278.     int     dx, dy;
  279.     int     dw, dh;
  280.     int     sw, sh;
  281.     int     change_count;
  282.     int     linecount;
  283.     int     num_output_frames;
  284.     int     cur_output_frame;
  285.     int     pstamps_per_frame;
  286.     int     num_output_pstamps;
  287.     int     cur_pstamp;
  288.     int     cur_pstamp_within_frame;
  289.     int     num_cel_frames;
  290.     double    cur_cel_frame;
  291.     double    offset_to_nextframe;
  292.     Screen    *celscrn;
  293.     Screen    *picscrn;
  294.  
  295.     /*------------------------------------------------------------------------
  296.      * ask permission before wiping out the current flic and/or cel.
  297.      *----------------------------------------------------------------------*/
  298.  
  299.     if (0 != (change_count = GetChangeCount())) {
  300.         if (!Qquestion(replace_flic_prompt, change_count))
  301.             return Err_abort;
  302.     }
  303.  
  304.     if (CelExists()) {
  305.         if (!is_okay_to_replace_cel) {
  306.             if (!Qquestion(replace_cel_prompt))
  307.                 return Err_abort;
  308.         }
  309.     }
  310.     is_okay_to_replace_cel = TRUE; // only ask permission once
  311.  
  312.     /*------------------------------------------------------------------------
  313.      * ask for the input flic/cel name, then load it as an AnimCel.
  314.      *----------------------------------------------------------------------*/
  315.  
  316.     if (!Qfile(".FL?;.CEL;.*", "Summarize", flicpath, flicpath, FALSE, disk_flicpath_prompt))
  317.         return Err_abort;
  318.  
  319.     if (Success < (err = LoadCel(flicpath))) {
  320.         Qerror(err, "Cannot load flic/cel file '%s'", flicpath);
  321.         err = Err_reported;
  322.         goto CLEANUP_EXIT;
  323.     }
  324.  
  325.     if (1 >= (num_cel_frames = CelFrameCount())) {
  326.         Qtext("Cannot create a summary of a single-frame flic!");
  327.         err = Err_reported;
  328.         goto CLEANUP_EXIT;
  329.     }
  330.  
  331.     /*------------------------------------------------------------------------
  332.      * figure out how many input frames we have, how many postage stamps we
  333.      * can put on one output frame, and how many output frames the user wants.
  334.      *----------------------------------------------------------------------*/
  335.  
  336.     pstamps_per_frame = grid_dimension * grid_dimension;
  337.     cur_output_frame  = 0;
  338.  
  339.     if (pstamps_per_frame > num_cel_frames) {
  340.         num_output_frames  = 1;
  341.         num_output_pstamps = num_cel_frames;
  342.     } else {
  343.         num_output_frames  = ask_frame_count(num_cel_frames, pstamps_per_frame);
  344.         if (num_output_frames < 1) {
  345.             err = Err_abort;
  346.             goto CLEANUP_EXIT;
  347.         }
  348.         num_output_pstamps = num_output_frames * pstamps_per_frame;
  349.         if (num_output_pstamps > num_cel_frames)
  350.             num_output_pstamps = num_cel_frames;
  351.     }
  352.  
  353.     /*------------------------------------------------------------------------
  354.      * Set up the postage stamp sizes and placements, init the output frames.
  355.      *----------------------------------------------------------------------*/
  356.  
  357.     picscrn = GetPicScreen();
  358.     celscrn = GetCelScreen();
  359.  
  360.     SetFrameCount(1);                  // goto 1st frame, InitPstamp clears it
  361.     InitPstampScreen(picscrn);          // and lays in the 6-cube color palette.
  362.     SetFrameCount(num_output_frames); // now clone the right # of copies of it.
  363.  
  364.     cur_cel_frame        = 0.0;
  365.     offset_to_nextframe = (double)num_cel_frames / num_output_pstamps;
  366.     if (offset_to_nextframe < 1.0)
  367.         offset_to_nextframe = 1.0;
  368.  
  369.     GetScreenSize(picscrn, &dw, &dh);
  370.     dw = (dw / grid_dimension) - 1;
  371.     dh = (dh / grid_dimension) - 1;
  372.  
  373.     /*------------------------------------------------------------------------
  374.      * build the summary...
  375.      *----------------------------------------------------------------------*/
  376.  
  377.     for (cur_output_frame = 0;
  378.             cur_cel_frame < num_cel_frames;
  379.             ++cur_output_frame) {
  380.  
  381.         InitPstampScreen(picscrn);
  382.  
  383.         for (dy = 0, cur_pstamp_within_frame = 1;
  384.                 (cur_pstamp_within_frame <= pstamps_per_frame &&
  385.                  cur_cel_frame < num_cel_frames);
  386.                 dy += dh) {
  387.  
  388.             for (dx = 0, linecount = 0;
  389.                     (linecount < grid_dimension &&
  390.                      cur_pstamp_within_frame <= pstamps_per_frame &&
  391.                      cur_cel_frame < num_cel_frames);
  392.                     dx += dw, ++linecount) {
  393.  
  394.                 CelSetFrame((int)cur_cel_frame);
  395.                 printf("Processing frame %d, the %s of %d in the summary",
  396.                         (int)cur_cel_frame,
  397.                         ordinal(cur_pstamp), num_output_pstamps);
  398.                 MakePstamp(celscrn, picscrn, dx, dy, dw, dh, TRUE);
  399.                 ++cur_pstamp_within_frame;
  400.                 ++cur_pstamp;
  401.                 cur_cel_frame = cur_pstamp * offset_to_nextframe;
  402.             }
  403.         }
  404.         CleanupPstampScreen(picscrn);
  405.         NextFrame();
  406.     }
  407.  
  408. CLEANUP_EXIT:
  409.  
  410. #if __POCO__ < 178        // original Poco version didn't have a CelRelease()
  411.     CelGet(0,0,1,1);    // function, so we free the bulk of the resources
  412. #else                    // used by the cel we loaded by cutting out a 1-pixel
  413.     CelRelease();        // cel, which hardly uses any resource at all.    Later
  414. #endif                    // versions of Poco have a proper CelRelease().
  415.  
  416.     unprintf();
  417.     return err;
  418. }
  419.  
  420. void main(void)
  421. /*****************************************************************************
  422.  * drive main menu dialog, dispatch processing of selections.
  423.  ****************************************************************************/
  424. {
  425.     int option;
  426.     static char last_path[PATH_SIZE] = "";
  427.  
  428.     GlobalVarGet(disk_flicpath_gvar,last_path);
  429.     get_grid_choice(FALSE); // go load saved grid option from global var
  430.  
  431.     do    {
  432.         option = Qmenu(main_menu, Array_els(main_menu), main_menu_title);
  433.         switch (option) {
  434.           case 1:
  435.             summarize_current_flic();
  436.             break;
  437.           case 2:
  438.             summarize_disk_flic(last_path);
  439.             break;
  440.           case 3:
  441.             get_grid_choice(TRUE);
  442.             break;
  443.           case 4:
  444.             do_help();
  445.             break;
  446.           default:
  447.             break;
  448.         }
  449.     } while (option > 0);
  450.  
  451.     GlobalVarSet(disk_flicpath_gvar,last_path);
  452. }
  453.